#include "wx/wxprec.h"
#if wxUSE_COMBOCTRL

#include "wx/combo.h"

#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/combobox.h"
#include "wx/dcclient.h"
#include "wx/settings.h"
#endif

#include "wx/dcbuffer.h"

#if defined(__WXUNIVERSAL__)

#define TEXTCTRLXADJUST                 0 // position adjustment for wxTextCtrl, with zero indent
#define TEXTCTRLYADJUST                 0
#define TEXTXADJUST                     0 // how much is read-only text's x adjusted
#define DEFAULT_DROPBUTTON_WIDTH        19

#elif defined(__WXMSW__)

#define TEXTCTRLXADJUST                 2 // position adjustment for wxTextCtrl, with zero indent
#define TEXTCTRLYADJUST                 3
#define TEXTXADJUST                     0 // how much is read-only text's x adjusted
#define DEFAULT_DROPBUTTON_WIDTH        17

#elif defined(__WXGTK__)

#define TEXTCTRLXADJUST                 -1 // position adjustment for wxTextCtrl, with zero indent
#define TEXTCTRLYADJUST                 0
#define TEXTXADJUST                     1 // how much is read-only text's x adjusted
#define DEFAULT_DROPBUTTON_WIDTH        23

#elif defined(__WXMAC__)

#define TEXTCTRLXADJUST                 0 // position adjustment for wxTextCtrl, with zero indent
#define TEXTCTRLYADJUST                 0
#define TEXTXADJUST                     0 // how much is read-only text's x adjusted
#define DEFAULT_DROPBUTTON_WIDTH        22

#else

#define TEXTCTRLXADJUST                 0 // position adjustment for wxTextCtrl, with zero indent
#define TEXTCTRLYADJUST                 0
#define TEXTXADJUST                     0 // how much is read-only text's x adjusted
#define DEFAULT_DROPBUTTON_WIDTH        19

#endif

#ifndef wxCOMBOCONTROL_FULLY_FEATURED

BEGIN_EVENT_TABLE( wxGenericComboCtrl, wxComboCtrlBase )
  EVT_PAINT( wxGenericComboCtrl::OnPaintEvent )
  EVT_MOUSE_EVENTS( wxGenericComboCtrl::OnMouseEvent )
END_EVENT_TABLE()


IMPLEMENT_DYNAMIC_CLASS( wxGenericComboCtrl, wxComboCtrlBase )

void wxGenericComboCtrl::Init() {
}

bool wxGenericComboCtrl::Create( wxWindow *parent,
                                 wxWindowID id,
                                 const wxString& value,
                                 const wxPoint& pos,
                                 const wxSize& size,
                                 long style,
                                 const wxValidator& validator,
                                 const wxString& name ) {
  long border = style & wxBORDER_MASK;
  int tcBorder = wxNO_BORDER;
  #if defined(__WXUNIVERSAL__)
  if( !border ) {
    border = wxBORDER_SIMPLE;
  }
  #elif defined(__WXMSW__)
  if( !border ) {
    border = wxBORDER_SUNKEN;
  }
  #else
#define UNRELIABLE_TEXTCTRL_BORDER
  if( !border ) {
    if( style & wxCB_READONLY ) {
      m_widthCustomBorder = 1;
    } else {
      m_widthCustomBorder = 0;
      tcBorder = 0;
    }
  } else {
    tcBorder = border;
  }
  border = wxBORDER_NONE;
  Customize( wxCC_BUTTON_OUTSIDE_BORDER |
             wxCC_NO_TEXT_AUTO_SELECT );
  #endif
  style = ( style & ~( wxBORDER_MASK ) ) | border;
  if( style & wxCC_STD_BUTTON ) {
    m_iFlags |= wxCC_POPUP_ON_MOUSE_UP;
  }
  if( !wxComboCtrlBase::Create( parent,
                                id,
                                value,
                                pos,
                                size,
                                style | wxFULL_REPAINT_ON_RESIZE,
                                wxDefaultValidator,
                                name ) ) {
    return false;
  }
  CreateTextCtrl( tcBorder, validator );
  InstallInputHandlers();
  SetBackgroundStyle( wxBG_STYLE_CUSTOM );
  SetInitialSize( size );
  return true;
}

wxGenericComboCtrl::~wxGenericComboCtrl() {
}

void wxGenericComboCtrl::OnResize() {
  CalculateAreas( DEFAULT_DROPBUTTON_WIDTH );
  PositionTextCtrl( TEXTCTRLXADJUST, TEXTCTRLYADJUST );
}

void wxGenericComboCtrl::OnPaintEvent( wxPaintEvent& ( event ) ) {
  wxSize sz = GetClientSize();
  wxAutoBufferedPaintDC dc( this );
  const wxRect& rectb = m_btnArea;
  wxRect rect = m_tcArea;
  if( m_widthCustomBorder ) {
    int customBorder = m_widthCustomBorder;
    wxPen pen1( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ),
                customBorder,
                wxSOLID );
    dc.SetPen( pen1 );
    wxRect rect2( 0, 0, sz.x, sz.y );
    if( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE ) {
      rect2 = m_tcArea;
      if( customBorder == 1 ) {
        rect2.Inflate( 1 );
      } else {
        rect2.x -= 1;
        rect2.y -= 1;
        rect2.width += 1 + customBorder;
        rect2.height += 1 + customBorder;
      }
    }
    dc.SetBrush( *wxTRANSPARENT_BRUSH );
    dc.DrawRectangle( rect2 );
  }
  #if defined(__WXMAC__) || defined(__WXGTK__)  // see note in OnThemeChange
  wxColour winCol = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
  #else
  wxColour winCol = GetBackgroundColour();
  #endif
  dc.SetBrush( winCol );
  dc.SetPen( winCol );
  dc.DrawRectangle( rect );
  if( !m_btn ) {
    DrawButton( dc, rectb, 0 );
  }
  if( ( !m_text || m_widthCustomPaint ) ) {
    wxASSERT( m_widthCustomPaint >= 0 );
    if( m_text ) {
      rect.width = m_widthCustomPaint;
    }
    dc.SetFont( GetFont() );
    dc.SetClippingRegion( rect );
    if( m_popupInterface ) {
      m_popupInterface->PaintComboControl( dc, rect );
    } else
    { wxComboPopup::DefaultPaintComboControl( this, dc, rect ); }
  }
}

void wxGenericComboCtrl::OnMouseEvent( wxMouseEvent& event ) {
  int mx = event.m_x;
  bool isOnButtonArea = m_btnArea.Contains( mx, event.m_y );
  int handlerFlags = isOnButtonArea ? wxCC_MF_ON_BUTTON : 0;
  if( PreprocessMouseEvent( event, handlerFlags ) ) {
    return;
  }
  const bool ctrlIsButton = wxPlatformIs( wxOS_WINDOWS );
  if( ctrlIsButton && ( m_windowStyle & ( wxCC_SPECIAL_DCLICK | wxCB_READONLY ) ) == wxCB_READONLY ) {
    handlerFlags |= wxCC_MF_ON_BUTTON;
    if( HandleButtonMouseEvent( event, handlerFlags ) ) {
      return;
    }
  } else {
    if( isOnButtonArea || HasCapture() ||
        ( m_widthCustomPaint && mx < ( m_tcArea.x + m_widthCustomPaint ) ) ) {
      handlerFlags |= wxCC_MF_ON_CLICK_AREA;
      if( HandleButtonMouseEvent( event, handlerFlags ) ) {
        return;
      }
    } else if( m_btnState ) {
      m_btnState = 0;
      RefreshRect( m_btnArea );
    }
  }
  HandleNormalMouseEvent( event );
}

void wxGenericComboCtrl::SetCustomPaintWidth( int width ) {
  #ifdef UNRELIABLE_TEXTCTRL_BORDER
  wxTextCtrl* tc = GetTextCtrl();
  if( tc && ( m_iFlags & wxCC_BUTTON_OUTSIDE_BORDER ) ) {
    int borderType = tc->GetWindowStyle() & wxBORDER_MASK;
    int tcCreateStyle = -1;
    if( width > 0 ) {
      if( borderType != wxNO_BORDER ) {
        m_widthCustomBorder = 1;
        tcCreateStyle = wxNO_BORDER;
      }
    } else if( width == 0 ) {
      if( borderType == wxNO_BORDER ) {
        m_widthCustomBorder = 0;
        tcCreateStyle = 0;
      }
    }
    if( tcCreateStyle != -1 ) {
      tc->RemoveEventHandler( m_textEvtHandler );
      delete m_textEvtHandler;
      #if wxUSE_VALIDATORS
      wxValidator* pValidator = tc->GetValidator();
      if( pValidator ) {
        pValidator = ( wxValidator* ) pValidator->Clone();
        CreateTextCtrl( tcCreateStyle, *pValidator );
        delete pValidator;
      } else
      #endif
      {
        CreateTextCtrl( tcCreateStyle, wxDefaultValidator );
      }
      InstallInputHandlers();
    }
  }
  #endif // UNRELIABLE_TEXTCTRL_BORDER
  wxComboCtrlBase::SetCustomPaintWidth( width );
}

bool wxGenericComboCtrl::IsKeyPopupToggle( const wxKeyEvent& event ) const {
  int keycode = event.GetKeyCode();
  bool isPopupShown = IsPopupShown();
  if( isPopupShown ) {
    if( keycode == WXK_ESCAPE ||
        ( keycode == WXK_UP && event.AltDown() ) ) {
      return true;
    }
  } else {
    if( keycode == WXK_DOWN && event.AltDown() ) {
      return true;
    }
  }
  return false;
}

#ifdef __WXUNIVERSAL__

bool wxGenericComboCtrl::PerformAction( const wxControlAction& action, long numArg, const wxString& strArg ) {
  bool processed = false;
  if( action == wxACTION_COMBOBOX_POPUP ) {
    if( !IsPopupShown() ) {
      ShowPopup();
      processed = true;
    }
  } else if( action == wxACTION_COMBOBOX_DISMISS ) {
    if( IsPopupShown() ) {
      HidePopup();
      processed = true;
    }
  }
  if( !processed ) {
    return wxControl::PerformAction( action, numArg, strArg );
  }
  return true;
}

#endif

#ifndef _WX_COMBOCONTROL_H_
IMPLEMENT_DYNAMIC_CLASS( wxComboCtrl, wxGenericComboCtrl )
#endif

#endif

#endif
